<!DOCTYPE html>
<html>
<head>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id='UA-133422980-2"></script>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());

	  gtag('config', 'UA-133422980-2');
	</script>

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>
		gem5: Action code blocks 
	</title>

	<!-- SITE FAVICON -->
	<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>

	<link rel="canonical" href="http://localhost:4000/documentation/learning_gem5/part3/cache-actions/">
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>

	<!-- FAVICON -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

	<!-- BOOTSTRAP -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

	<!-- CUSTOM CSS -->
	<link rel="stylesheet" href="/css/main.css">
</head>


<body>
	<nav class="navbar navbar-expand-md navbar-light bg-light">
  <a class="navbar-brand" href="/">
		<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=55px>
	</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <!-- LIST FOR NAVBAR -->
    <ul class="navbar-nav ml-auto">
      <!-- HOME -->
      <li class="nav-item ">
        <a class="nav-link" href="/">Home</a>
      </li>

      <!-- ABOUT -->
			<li class="nav-item dropdown ">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					About
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="/about">About gem5</a>
          <a class="dropdown-item" href="/publications">Publications</a>
          <a class="dropdown-item" href="/governance">Governance</a>
				</div>
			</li>

      <!-- DOCUMENTATION -->
			<li class="nav-item dropdown active">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					Documentation
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
					<!-- Pull navigation from _data/documentation.yml -->
					
            <a class="dropdown-item" href="/documentation">gem5 documentation</a>
					
            <a class="dropdown-item" href="/documentation/learning_gem5/introduction">Learning gem5</a>
					
            <a class="dropdown-item" href="http://doxygen.gem5.org/release/current/index.html">gem5 Doxygen</a>
					
            <a class="dropdown-item" href="/documentation/reporting_problems">Reporting Problems</a>
					
				</div>
			</li>

      <!-- EVENTS -->
			<li class="nav-item dropdown ">
        <a class="nav-link" href="/events/">Events</a>
			</li>

      <!-- CONTRIBUTING -->
      <li class="nav-item ">
        <a class="nav-link" href="/contributing">Contributing</a>
      </li>

      <!-- BLOG -->
      <li class="nav-item ">
        <a class="nav-link" href="/blog">Blog</a>
      </li>

      <!-- SEARCH -->
			<li class="nav-item ">
        <a class="nav-link" href="/search">Search</a>
      </li>
    </ul>
  </div>
</nav>

	<main>
		<div class="sidenav-top">
  <div class="sidenav-brand bg-light">
    <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="55px"></a>
  </div>
  <div class="search">
    <form action="/search" method="get">
      <!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
      <input type="text" name="query">
      <button type="submit" name="submit"><i class="fa fa-search"></i></button>
    </form>
  </div>
</div>
<div class="sidenav">
  <!-- Pull navigation from _data/documentation.yml -->
  
    
  
    
    
      <a class="item" href="/documentation/learning_gem5/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
        Introduction
      </a>
      <div class="collapse " id="introduction">
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part1" role="button" aria-expanded="false" aria-controls="collapseExample">
        Getting Started
      </a>
      <div class="collapse " id="part1">
        
          <a class="subitem " href="/documentation/learning_gem5/part1/building">Building gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/simple_config">Creating a simple configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/cache_config">Adding cache to configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/gem5_stats">Understanding gem5 statistics and output</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/example_configs">Using the default configuration scripts</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part2" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modifying/Extending
      </a>
      <div class="collapse " id="part2">
        
          <a class="subitem " href="/documentation/learning_gem5/part2/environment">Setting up your development environment</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/helloobject">Creating a very simple SimObject</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/debugging">Debugging gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/events">Event-driven programming</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/parameters">Adding parameters to SimObjects and more events</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/memoryobject">Creating SimObjects in the memory system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/simplecache">Creating a simple cache object</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part3" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modeling Cache Coherence with Ruby
      </a>
      <div class="collapse show" id="part3">
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIintro">Introduction to Ruby</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-intro">MSI example cache protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-declarations">Declaring a state machine</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-in-ports">In port code blocks</a>
        
          <a class="subitem active" href="/documentation/learning_gem5/part3/cache-actions">Action code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-transitions">Transition code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/directory">MSI Directory implementation</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIbuilding">Compiling a SLICC protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/configuration">Configuring a simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/running">Running the simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIdebugging">Debugging SLICC Protocols</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/simple-MI_example">Configuring for a standard protocol</a>
        
      </div>
    
      <a class="item" href="/documentation/learning_gem5/gem5_101/" role="button" aria-expanded="false" aria-controls="collapseExample">
        gem5 101
      </a>
      <div class="collapse " id="gem5_101">
        
      </div>
    
    
  
    
  
    
  
</div>


<div class="container" id="doc-container">
  <div class="edit"><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Edit this page</a></div>
  <b>authors:</b> Jason Lowe-Power<br>
  

  <br>
  <h1 id="action-code-blocks">Action code blocks</h1>

<p>The next section of the state machine file is the action blocks. The
action blocks are executed during a transition from one state to
another, and are called by the transition code blocks (which we will
discuss in the next section &lt;MSI-transitions-section&gt;). Actions are
<em>single action</em> blocks. Some examples are “send a message to the
directory” and “pop the head of the buffer”. Each action should be small
and only perform a single action.</p>

<p>The first action we will implement is an action to send a GetS request
to the directory. We need to send a GetS request to the directory
whenever we want to read some data that is not in the Modified or Shared
states in our cache. As previously mentioned, there are three variables
that are automatically populated inside the action block (like the
<code class="highlighter-rouge">in_msg</code> in <code class="highlighter-rouge">peek</code> blocks). <code class="highlighter-rouge">address</code> is the address that was passed
into the <code class="highlighter-rouge">trigger</code> function, <code class="highlighter-rouge">cache_entry</code> is the cache entry passed
into the <code class="highlighter-rouge">trigger</code> function, and <code class="highlighter-rouge">tbe</code> is the TBE passed into the
<code class="highlighter-rouge">trigger</code> function.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">sendGetS</span><span class="p">,</span> <span class="err">'</span><span class="n">gS</span><span class="err">'</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send GetS to the directory"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">enqueue</span><span class="p">(</span><span class="n">request_out</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceRequestType</span><span class="o">:</span><span class="n">GetS</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">mapAddressToMachine</span><span class="p">(</span><span class="n">address</span><span class="p">,</span>
                                <span class="nl">MachineType:</span><span class="n">Directory</span><span class="p">));</span>
        <span class="c1">// See mem/protocol/RubySlicc_Exports.sm for possible sizes.</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Control</span><span class="p">;</span>
        <span class="c1">// Set that the requestor is this machine so we get the response.</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Requestor</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When specifying the action block, there are two parameters: a
description and a “shorthand”. These two parameters are used in the HTML
table generation. The shorthand shows up in the transition cell, so it
should be as short as possible. SLICC provides a special syntax to allow
for bold (‘’), superscript (‘\^’), and spaces (‘_’) in the shorthand to
help keep them short. Second, the description also shows up in the HTML
table when you click on a particular action. The description can be
longer and help explain what the action does.</p>

<p>Next, in this action we are going to send a message to the directory on
the <code class="highlighter-rouge">request_out</code> port as declared above the <code class="highlighter-rouge">in_port</code> blocks. The
<code class="highlighter-rouge">enqueue</code> function is similar to the <code class="highlighter-rouge">peek</code> function since it requires a
code block. <code class="highlighter-rouge">enqueue</code>, however, has the special variable <code class="highlighter-rouge">out_msg</code>. In
the <code class="highlighter-rouge">enqueue</code> block, you can modify the <code class="highlighter-rouge">out_msg</code> with the current data.</p>

<p>The <code class="highlighter-rouge">enqueue</code> block takes three parameters, the message buffer to send
the message, the type of the message, and a latency. This latency (1
cycle in the example above and throughout this cache controller) is the
<em>cache latency</em>. This is where you specify the latency of accessing the
cache, in this case for a miss. Below we will see that specifying the
latency for a hit is similar.</p>

<p>Inside the <code class="highlighter-rouge">enqueue</code> block is where the message data is populated. For
the address of the request, we can use the automatically populated
<code class="highlighter-rouge">address</code> variable. We are sending a GetS message, so we use that
message type. Next, we need to specify the destination of the message.
For this, we use the <code class="highlighter-rouge">mapAddressToMachine</code> function that takes the
address and the machine type we are sending to. This will look up in the
correct <code class="highlighter-rouge">MachineID</code> based on the address. We call <code class="highlighter-rouge">Destination.add</code>
because <code class="highlighter-rouge">Destination</code> is a <code class="highlighter-rouge">NetDest</code> object, or a bitmap of all
<code class="highlighter-rouge">MachineID</code>.</p>

<p>Finally, we need to specify the message size (from
<code class="highlighter-rouge">mem/protocol/RubySlicc_Exports.sm</code>) and set ourselves as the requestor.
By setting this <code class="highlighter-rouge">machineID</code> as the requestor, it will allow the
directory to respond to this cache or forward it to another cache to
respond to this request.</p>

<p>Similarly, we can create actions for sending other get and put requests.
Note that get requests represent requests for data and put requests
represent requests where we downgrading or evicting our copy of the
data.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">sendGetM</span><span class="p">,</span> <span class="s">"gM"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send GetM to the directory"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">enqueue</span><span class="p">(</span><span class="n">request_out</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceRequestType</span><span class="o">:</span><span class="n">GetM</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">mapAddressToMachine</span><span class="p">(</span><span class="n">address</span><span class="p">,</span>
                                <span class="nl">MachineType:</span><span class="n">Directory</span><span class="p">));</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Control</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Requestor</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">sendPutS</span><span class="p">,</span> <span class="s">"pS"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send PutS to the directory"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">enqueue</span><span class="p">(</span><span class="n">request_out</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceRequestType</span><span class="o">:</span><span class="n">PutS</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">mapAddressToMachine</span><span class="p">(</span><span class="n">address</span><span class="p">,</span>
                                <span class="nl">MachineType:</span><span class="n">Directory</span><span class="p">));</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Control</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Requestor</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">sendPutM</span><span class="p">,</span> <span class="s">"pM"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send putM+data to the directory"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">enqueue</span><span class="p">(</span><span class="n">request_out</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceRequestType</span><span class="o">:</span><span class="n">PutM</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">mapAddressToMachine</span><span class="p">(</span><span class="n">address</span><span class="p">,</span>
                                <span class="nl">MachineType:</span><span class="n">Directory</span><span class="p">));</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Data</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Requestor</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we need to specify an action to send data to another cache in the
case that we get a forwarded request from the directory for another
cache. In this case, we have to peek into the request queue to get other
data from the requesting message. This peek code block is exactly the
same as the ones in the <code class="highlighter-rouge">in_port</code>. When you nest an <code class="highlighter-rouge">enqueue</code> block in a
<code class="highlighter-rouge">peek</code> block both <code class="highlighter-rouge">in_msg</code> and <code class="highlighter-rouge">out_msg</code> variables are available. This
is needed so we know which other cache to send the data to.
Additionally, in this action we use the <code class="highlighter-rouge">cache_entry</code> variable to get
the data to send to the other cache.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">sendCacheDataToReq</span><span class="p">,</span> <span class="s">"cdR"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send cache data to requestor"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">forward_in</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">enqueue</span><span class="p">(</span><span class="n">response_out</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceResponseType</span><span class="o">:</span><span class="n">Data</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">in_msg</span><span class="p">.</span><span class="n">Requestor</span><span class="p">);</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Data</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Sender</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we specify actions for sending data to the directory and sending
an invalidation ack to the original requestor on a forward request when
this cache does not have the data.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">sendCacheDataToDir</span><span class="p">,</span> <span class="s">"cdD"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send the cache data to the dir"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">enqueue</span><span class="p">(</span><span class="n">response_out</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceResponseType</span><span class="o">:</span><span class="n">Data</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">mapAddressToMachine</span><span class="p">(</span><span class="n">address</span><span class="p">,</span>
                                <span class="nl">MachineType:</span><span class="n">Directory</span><span class="p">));</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Data</span><span class="p">;</span>
        <span class="n">out_msg</span><span class="p">.</span><span class="n">Sender</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">sendInvAcktoReq</span><span class="p">,</span> <span class="s">"iaR"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Send inv-ack to requestor"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">forward_in</span><span class="p">,</span> <span class="n">RequestMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">enqueue</span><span class="p">(</span><span class="n">response_out</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">addr</span> <span class="o">:=</span> <span class="n">address</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Type</span> <span class="o">:=</span> <span class="n">CoherenceResponseType</span><span class="o">:</span><span class="n">InvAck</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Destination</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">in_msg</span><span class="p">.</span><span class="n">Requestor</span><span class="p">);</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">MessageSize</span> <span class="o">:=</span> <span class="n">MessageSizeType</span><span class="o">:</span><span class="n">Control</span><span class="p">;</span>
            <span class="n">out_msg</span><span class="p">.</span><span class="n">Sender</span> <span class="o">:=</span> <span class="n">machineID</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Another required action is to decrement the number of acks we are
waiting for. This is used when we get a invalidation ack from another
cache to track the total number of acks. For this action, we assume that
there is a valid TBE and modify the implicit <code class="highlighter-rouge">tbe</code> variable in the
action block.</p>

<p>Additionally, we have another example of making debugging easier in
protocols: <code class="highlighter-rouge">APPEND_TRANSITION_COMMENT</code>. This function takes a string, or
something that can easily be converted to a string (e.g., <code class="highlighter-rouge">int</code>) as a
parameter. It modifies the <em>protocol trace</em> output, which we will
discuss in the <a href="../MSIdebugging">debugging section</a>. On each
protocol trace line that executes this action it will print the total
number of acks this cache is still waiting on. This is useful since the
number of remaining acks is part of the cache block state.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">decrAcks</span><span class="p">,</span> <span class="s">"da"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Decrement the number of acks"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">));</span>
    <span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span> <span class="o">:=</span> <span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">APPEND_TRANSITION_COMMENT</span><span class="p">(</span><span class="s">"Acks: "</span><span class="p">);</span>
    <span class="n">APPEND_TRANSITION_COMMENT</span><span class="p">(</span><span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We also need an action to store the acks when we receive a message from
the directory with an ack count. For this action, we peek into the
directory’s response message to get the number of acks and store them in
the (required to be valid) TBE.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">storeAcks</span><span class="p">,</span> <span class="s">"sa"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Store the needed acks to the TBE"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">));</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">response_in</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span> <span class="o">:=</span> <span class="n">in_msg</span><span class="p">.</span><span class="n">Acks</span> <span class="o">+</span> <span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">tbe</span><span class="p">.</span><span class="n">AcksOutstanding</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The next set of actions are to respond to CPU requests on hits and
misses. For these actions, we need to notify the sequencer (the
interface between Ruby and the rest of gem5) of the new data. In the
case of a store, we give the sequencer a pointer to the data block and
the sequencer updates the data in-place.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">loadHit</span><span class="p">,</span> <span class="s">"Lh"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Load hit"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">cacheMemory</span><span class="p">.</span><span class="n">setMRU</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">);</span>
    <span class="n">sequencer</span><span class="p">.</span><span class="n">readCallback</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">externalLoadHit</span><span class="p">,</span> <span class="s">"xLh"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"External load hit (was a miss)"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">response_in</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cacheMemory</span><span class="p">.</span><span class="n">setMRU</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">);</span>
        <span class="c1">// Forward the type of machine that responded to this request</span>
        <span class="c1">// E.g., another cache or the directory. This is used for tracking</span>
        <span class="c1">// statistics.</span>
        <span class="n">sequencer</span><span class="p">.</span><span class="n">readCallback</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
                               <span class="n">machineIDToMachineType</span><span class="p">(</span><span class="n">in_msg</span><span class="p">.</span><span class="n">Sender</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">storeHit</span><span class="p">,</span> <span class="s">"Sh"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Store hit"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">cacheMemory</span><span class="p">.</span><span class="n">setMRU</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">);</span>
    <span class="c1">// The same as the read callback above.</span>
    <span class="n">sequencer</span><span class="p">.</span><span class="n">writeCallback</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">externalStoreHit</span><span class="p">,</span> <span class="s">"xSh"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"External store hit (was a miss)"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">response_in</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cacheMemory</span><span class="p">.</span><span class="n">setMRU</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">);</span>
        <span class="n">sequencer</span><span class="p">.</span><span class="n">writeCallback</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
                               <span class="c1">// Note: this could be the last ack.</span>
                               <span class="n">machineIDToMachineType</span><span class="p">(</span><span class="n">in_msg</span><span class="p">.</span><span class="n">Sender</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">forwardEviction</span><span class="p">,</span> <span class="s">"e"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"sends eviction notification to CPU"</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">send_evictions</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sequencer</span><span class="p">.</span><span class="n">evictionCallback</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In each of these actions, it is vital that we call <code class="highlighter-rouge">setMRU</code> on the cache
entry. The <code class="highlighter-rouge">setMRU</code> function is what allows the replacement policy to
know which blocks are most recently accessed. If you leave out the
<code class="highlighter-rouge">setMRU</code> call, the replacement policy will not operate correctly!</p>

<p>On loads and stores, we call the <code class="highlighter-rouge">read/writeCallback</code> function on the
<code class="highlighter-rouge">sequencer</code>. This notifies the sequencer of the new data or allows it to
write the data into the data block. These functions take four parameters
(the last parameter is optional): address, data block, a boolean for if
the original request was a miss, and finally, an optional <code class="highlighter-rouge">MachineType</code>.
The final optional parameter is used for tracking statistics on where
the data for the request was found. It allows you to track whether the
data comes from cache-to-cache transfers or from memory.</p>

<p>Finally, we also have an action to forward evictions to the CPU. This is
required for gem5’s out-of-order models to squash speculative loads if
the cache block is evicted before the load is committed. We use the
parameter specified at the top of the state machine file to check if
this is needed or not.</p>

<p>Next, we have a set of cache management actions that allocate and free
cache entries and TBEs. To create a new cache entry, we must have space
in the <code class="highlighter-rouge">CacheMemory</code> object. Then, we can call the <code class="highlighter-rouge">allocate</code> function.
This allocate function doesn’t actually allocate the host memory for the
cache entry since this controller specialized the <code class="highlighter-rouge">Entry</code> type, which is
why we need to pass a <code class="highlighter-rouge">new Entry</code> to the <code class="highlighter-rouge">allocate</code> function.</p>

<p>Additionally, in these actions we call <code class="highlighter-rouge">set_cache_entry</code>,
<code class="highlighter-rouge">unset_cache_entry</code>, and similar functions for the TBE. These set and
unset the implicit variables that were passed in via the <code class="highlighter-rouge">trigger</code>
function. For instance, when allocating a new cache block, we call
<code class="highlighter-rouge">set_cache_entry</code> and in all actions proceeding <code class="highlighter-rouge">allocateCacheBlock</code> the
<code class="highlighter-rouge">cache_entry</code> variable will be valid.</p>

<p>There is also an action that copies the data from the cache data block
to the TBE. This allows us to keep the data around even after removing
the cache block until we are sure that this cache no longer are
responsible for the data.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">allocateCacheBlock</span><span class="p">,</span> <span class="s">"a"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Allocate a cache block"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_invalid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">cacheMemory</span><span class="p">.</span><span class="n">cacheAvail</span><span class="p">(</span><span class="n">address</span><span class="p">));</span>
    <span class="n">set_cache_entry</span><span class="p">(</span><span class="n">cacheMemory</span><span class="p">.</span><span class="n">allocate</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="k">new</span> <span class="n">Entry</span><span class="p">));</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">deallocateCacheBlock</span><span class="p">,</span> <span class="s">"d"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Deallocate a cache block"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">cacheMemory</span><span class="p">.</span><span class="n">deallocate</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
    <span class="c1">// clear the cache_entry variable (now it's invalid)</span>
    <span class="n">unset_cache_entry</span><span class="p">();</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">writeDataToCache</span><span class="p">,</span> <span class="s">"wd"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Write data to the cache"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">peek</span><span class="p">(</span><span class="n">response_in</span><span class="p">,</span> <span class="n">ResponseMsg</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
        <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">in_msg</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">allocateTBE</span><span class="p">,</span> <span class="s">"aT"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Allocate TBE"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_invalid</span><span class="p">(</span><span class="n">tbe</span><span class="p">));</span>
    <span class="n">TBEs</span><span class="p">.</span><span class="n">allocate</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
    <span class="c1">// this updates the tbe variable for other actions</span>
    <span class="n">set_tbe</span><span class="p">(</span><span class="n">TBEs</span><span class="p">[</span><span class="n">address</span><span class="p">]);</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">deallocateTBE</span><span class="p">,</span> <span class="s">"dT"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Deallocate TBE"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">));</span>
    <span class="n">TBEs</span><span class="p">.</span><span class="n">deallocate</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
    <span class="c1">// this makes the tbe variable invalid</span>
    <span class="n">unset_tbe</span><span class="p">();</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">copyDataFromCacheToTBE</span><span class="p">,</span> <span class="s">"Dct"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Copy data from cache to TBE"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">));</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">));</span>
    <span class="n">tbe</span><span class="p">.</span><span class="n">DataBlk</span> <span class="o">:=</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The next set of actions are for managing the message buffers. We need to
add actions to pop the head message off of the buffers after the message
has been satisfied. The <code class="highlighter-rouge">dequeue</code> function takes a single parameter, a
time for the dequeue to take place. Delaying the dequeue for a cycle
prevents the <code class="highlighter-rouge">in_port</code> logic from consuming another message from the
same message buffer in a single cycle.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">popMandatoryQueue</span><span class="p">,</span> <span class="s">"pQ"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Pop the mandatory queue"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mandatory_in</span><span class="p">.</span><span class="n">dequeue</span><span class="p">(</span><span class="n">clockEdge</span><span class="p">());</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">popResponseQueue</span><span class="p">,</span> <span class="s">"pR"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Pop the response queue"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">response_in</span><span class="p">.</span><span class="n">dequeue</span><span class="p">(</span><span class="n">clockEdge</span><span class="p">());</span>
<span class="p">}</span>

<span class="n">action</span><span class="p">(</span><span class="n">popForwardQueue</span><span class="p">,</span> <span class="s">"pF"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Pop the forward queue"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">forward_in</span><span class="p">.</span><span class="n">dequeue</span><span class="p">(</span><span class="n">clockEdge</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Finally, the last action is a stall. Below, we are using a “z_stall”,
which is the simplest kind of stall in SLICC. By leaving the action
blank, it generates a “protocol stall” in the <code class="highlighter-rouge">in_port</code> logic which
stalls all messages from being processed in the current message buffer
and all lower priority message buffer. Protocols using “z_stall” are
usually simpler, but lower performance since a stall on a high priority
buffer can stall many requests that may not need to be stalled.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">action</span><span class="p">(</span><span class="n">stall</span><span class="p">,</span> <span class="s">"z"</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Stall the incoming request"</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// z_stall</span>
<span class="p">}</span>
</code></pre></div></div>

<p>There are two other ways to deal with messages that cannot currently be
processed that can improve the performance of protocols. (Note: We will
not be using these more complicated techniques in this simple example
protocol.) The first is <code class="highlighter-rouge">recycle</code>. The message buffers have a <code class="highlighter-rouge">recycle</code>
function that moves the request on the head of the queue to the tail.
This allows other requests in the buffer or requests in other buffers to
be processed immediately. <code class="highlighter-rouge">recycle</code> actions often improve the
performance of protocols significantly.</p>

<p>However, <code class="highlighter-rouge">recycle</code> is not very realistic when compared to real
implementations of cache coherence. For a more realistic
high-performance solution to stalling messages, Ruby provides the
<code class="highlighter-rouge">stall_and_wait</code> function on message buffers. This function takes the
head request and moves it into a separate structure tagged by an
address. The address is user-specified, but is usually the request’s
address. Later, when the blocked request can be handled, there is
another function <code class="highlighter-rouge">wakeUpBuffers(address)</code> which will wake up all
requests stalled on <code class="highlighter-rouge">address</code> and <code class="highlighter-rouge">wakeUpAllBuffers()</code> that wakes up all
of the stalled requests. When a request is “woken up” it is placed back
into the message buffer to be subsequently processed.</p>

  <br>

  <!-- RETRIVE PREVIOUS PAGE LINK -->
  
    
  
    
  
    
  
    
  

  <!-- RETRIEVE NEXT PAGE LINK -->
  
    
  
    
  
    
  
    
  


  <div class="navbuttons">
    
      <a href=""><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a>
    

    
      <a href=""><button type="button" class="btn btn-outline-primary">NEXT</button></a>
    
  </div>
</div>

	</main>
	<footer class="page-footer">
	<div class="container">
		<div class="row">

			<div class="col-12 col-sm-4">
				<p>gem5</p>
				<p><a href="/about">About</a></p>
				<p><a href="/publications">Publications</a></p>
				<p><a href="/contributing">Contributing</a></p>
				<p><a href="/governance">Governance</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Docs</p>
				<p><a href="/documentation">Documentation</a></p>
				<p><a href="http://gem5.org/Documentation">Old Documentation</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5">Source</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Help</p>
				<p><a href="/search">Search</a></p>
				<p><a href="/mailing_lists">Mailing Lists</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Website Source</a></p>
			<br></div>

		</div>
	</div>
</footer>


	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
	<script src="https://unpkg.com/commentbox.io/dist/commentBox.min.js"></script>

	<script>
	  // When the user scrolls down 20px from the top of the document, show the button
	  window.onscroll = function() {scrollFunction()};

	  function scrollFunction() {
	      if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
	          document.getElementById("myBtn").style.display = "block";
	      } else {
	          document.getElementById("myBtn").style.display = "none";
	      }
	  }

	  // When the user clicks on the button, scroll to the top of the document
	  function topFunction() {
	      document.body.scrollTop = 0;
	      document.documentElement.scrollTop = 0;
	  }

		import commentBox from 'commentbox.io';
		// or
		const commentBox = require('commentbox.io');
		// or if using the CDN, it will be available as a global "commentBox" variable.

		commentBox('my-project-id');

	</script>

</body>


</html>
